from package import Package
from socketbase import Server, Client, SocketBase
from qpyshare_sharelist import QPyShare_ShareList
from PyQt4 import QtCore, QtGui
import os,sys, md5

class QPyShare_Core(QtCore.QObject):
    
    state_Disconnected = 0
    state_Connecting = 1 #or server-listening
    state_Connected = 2 #waiting for handshake
    state_Connected_HS_OK = 3 #handshake ok
    
    version = "0.15"
    title = "QPyShare " + version
    
    def __init__(self, parent=None):
        QtCore.QObject.__init__(self, parent)
        
        QtCore.QCoreApplication.setOrganizationName("DARNeT")
        QtCore.QCoreApplication.setApplicationName("QPyShare")
        self.settings = QtCore.QSettings()
        self.initSettings()
        
        self.qpyshare_remote_ver = "0"
        self.state = QPyShare_Core.state_Disconnected
        self.shareList = QPyShare_ShareList(self)
        
        #recv , send
        self.commandsDictionary = {
            
            #Handshake sequence
            "HiFromServer": self.cmd_recv_HiFromServer_send_HiFromClient,
            "HiFromClient": self.cmd_recv_HiFromClient_send_HandShakeOK,
            "HandShakeOK": self.do_connectedOK,
            
            #Chat messages
            "Chat": self.cmd_chatMessage,
            
            #Disconnect sequence
            "Disconnect": self.cmd_recv_Disconnect_send_DisconnectOK,
            "DisconnectOK": self.cmd_recv_DisconnectOK,
            
            #AddFile
            "AddFile": self.shareList.addFile_fromPeer,
            "AddFileOK" : self.shareList.processPendingFiles,
            
            #StartFileTransfer
            "StartFileTransfer" : self.shareList.cmd_recv_StartFileTransfer_send_StartFileTransferOK,
            "StartFileTransferOK" : self.shareList.cmd_recv_FileDataOK_send_FileChunk,
            "RequestFileTransfer":  self.shareList.cmd_recv_RequestFileTransfer_send_StartFileTransfer,
            
            #FileTransfer Data
            "FileData" : self.shareList.cmd_recv_FileData_send_FileDataOK,
            "FileDataOK" : self.shareList.cmd_recv_FileDataOK_send_FileChunk,
            
            #FinishFileTransfer
            "EOF" : self.shareList.cmd_recv_EOF_send_EOFOK,
            "EOFOK" : self.shareList.cmd_recv_EOFOK_close,
            
            "PauseShare" : self.shareList.cmd_recv_PauseShare_send_PauseShareOK,
            "PauseShareOK" : self.shareList.cmd_recv_PauseShareOK,
            
            "ResumeShare": self.shareList.cmd_recv_ResumeShare_send_ResumeShareOK
            
        }
        
    def initSettings(self):
        keys = list(self.settings.allKeys())
        if keys.count(QtCore.QString("basepath")) == 0 :
            self.settings.setValue("basepath",QtCore.QVariant(QtCore.QDir.homePath() + "/"))
        if keys.count(QtCore.QString("chunksize")) == 0 :
            self.settings.setValue("chunksize",QtCore.QVariant(32*1024))
            
    def start(self,connType,ip,port):
        
        if self.state == QPyShare_Core.state_Disconnected:
            
            if connType == 0:
                self.socket = Server()
                self.socket.port = port
            elif connType == 1:
                self.socket = Client()
                self.socket.ip = ip
                self.socket.port = port
            
            self.connectSignals()
            self.socket.start()
            return True
            
        else:
            
            return False
            
    def disconnectSocket(self):
        #start disconnect sequence
        if self.state == self.state_Connected_HS_OK :
            pkg = Package("Disconnect")
            self.sendPkg(pkg)
        elif self.state == self.state_Connected or self.state == self.state_Connecting:
            self.socket.disconnectSocket()
        
    def stopServer(self):
        if self.socket.mode == SocketBase.modeServer:
            
            if self.state == QPyShare_Core.state_Connected or self.state == QPyShare_Core.state_Connected_HS_OK :
                self.disconnectSocket()
                
            self.socket.stop()
            
    def connectSignals(self):
        if self.socket.mode == SocketBase.modeServer:
            self.connect(self.socket,QtCore.SIGNAL("socketConnected()"), self.serverHandshake)
            
        self.connect(self.socket, QtCore.SIGNAL("socketConnecting()"), self.setConnecting)
        self.connect(self.socket, QtCore.SIGNAL("socketConnected()"), self.setConnected)
        self.connect(self.socket, QtCore.SIGNAL("socketDisconnected()"), self.setDisconnected)
        self.connect(self.socket,QtCore.SIGNAL("log(QString)"), self.log)
        self.connect(self.socket, QtCore.SIGNAL("socketNewData(QByteArray)"), self.readyData)
            
    def setConnecting(self):
        self.state = QPyShare_Core.state_Connecting
        self.emit(QtCore.SIGNAL("stateChanged()"))
    def setConnected(self):
        self.state = QPyShare_Core.state_Connected
        self.emit(QtCore.SIGNAL("stateChanged()"))
    def setDisconnected(self):
        if self.socket.mode == SocketBase.modeServer:
            if self.socket.socketServer.isListening() :
               self.state = QPyShare_Core.state_Connecting
            else:
                self.state = QPyShare_Core.state_Disconnected
        else:
            self.state = QPyShare_Core.state_Disconnected
            
        self.shareList.clearList()
        self.emit(QtCore.SIGNAL("stateChanged()"))

    def isConnectedHSOK(self):
        return self.state == QPyShare_Core.state_Connected_HS_OK
    
    #Server meets client at startup (HandShake)
    def serverHandshake(self):
        self.log("Starting HandShake")
        
        pkg = Package("HiFromServer")
        pkg.add("qpyshare_version",QPyShare_Core.version)
        
        self.sendPkg(pkg)
        
    def sendPkg(self,pkg):
        
        if self.state != QPyShare_Core.state_Disconnected:
            self.socket.socketSendData(pkg.toStr())
            return True
        else:
            return False
        
    def readyData(self,data):
        
        pkg = Package.fromStr(data)
        #self.log("New command recv: " + pkg.command)
        self.commandsDictionary[pkg.command](pkg)

    def sendChat(self,data):

        if self.state == QPyShare_Core.state_Connected_HS_OK:
                
            pkg = Package("Chat")
            pkg.add("msg",data)
            self.sendPkg(pkg)
            return True
        else:
            return False
    
    def log(self, msg):
        self.emit(QtCore.SIGNAL("log(QString)"), QtCore.QDateTime.currentDateTime().toString("(dd/MM/yy hh:mm:ss)") + " :: " + msg)

    #Add file from GUI (checks connection state before doing anything)
    def addFilePending(self, filename):
        if self.state == QPyShare_Core.state_Connected_HS_OK:
            self.shareList.addFilePending(filename)
            return True
        else:
            return False

    #COMMANDS
    
    #------------- HANDSHAKE SEQUENCE COMMANDS
    
    #Recibo HiFromServer envio HiFromClient
    def cmd_recv_HiFromServer_send_HiFromClient(self,orig_pkg):
        self.qpyshare_remote_ver = orig_pkg.get("qpyshare_version")
        self.log(QtCore.QCoreApplication.translate("QPyShare_Core","Connecting to QPyShare version %1").arg(self.qpyshare_remote_ver))
        
        pkg = Package("HiFromClient")
        pkg.add("qpyshare_version",QPyShare_Core.version)
        self.sendPkg(pkg)
        
    #Recibo HiFromClient envio HandShakeOK
    def cmd_recv_HiFromClient_send_HandShakeOK(self,orig_pkg):
        self.qpyshare_remote_ver = orig_pkg.get("qpyshare_version")
        self.log(QtCore.QCoreApplication.translate("QPyShare_Core","Connecting to QPyShare version %1").arg(self.qpyshare_remote_ver))
        
        pkg = Package("HandShakeOK")
        self.sendPkg(pkg)
        
        self.do_connectedOK()
    
    #Recibo HandShakeOK , do connectedOK
    def do_connectedOK(self, orig_pkg = None):
        self.log(QtCore.QCoreApplication.translate("QPyShare_Core","Connected and HandShake OK to %1").arg(self.socket.getRemoteInfo()))
        self.state = QPyShare_Core.state_Connected_HS_OK
        self.emit(QtCore.SIGNAL("stateChanged()"))
            
    #------------- CHAT COMMANDS
    
    #Recibo Chat y notifico al UI
    def cmd_chatMessage(self,orig_pkg):
        self.emit(QtCore.SIGNAL("newChatMessage(QString)"), orig_pkg.get("msg"))
    
    #------------- DISCONNECT SEQUENCE COMMANDS
    
    #Recibo Disconnect envio DisconnectOK , disconnect socket
    def cmd_recv_Disconnect_send_DisconnectOK(self,orig_pkg):
        self.log(QtCore.QCoreApplication.translate("QPyShare_Core","Disconnect sequence - Goodbye"))
        
        pkg = Package("DisconnectOK")
        self.sendPkg(pkg)
        
        self.socket.disconnectSocket()
        
    #Recibo DisconnectOK, disconnect socket
    def cmd_recv_DisconnectOK(self,orig_pkg):
        self.log(QtCore.QCoreApplication.translate("QPyShare_Core","Disconnect sequence OK - Goodbye"))
        self.socket.disconnectSocket()